package paf.model;

import java.util.ArrayList;
import paf.ui.Observer;

public class DiagramExpressionModel implements Observable{
	private ArrayList<Connection> arrConnections;
	private ArrayList<Class>arrClass;
	private ArrayList<UseCase>arrUseCases;
	private ArrayList<Observer> arrObservers;
	private static DiagramExpressionModel dem;

	private DiagramExpressionModel(){
		arrConnections = new ArrayList<Connection>();
		arrUseCases = new ArrayList<UseCase>();	
		arrClass = new ArrayList<Class>();	
		arrObservers = new ArrayList<Observer>();
	}

	public static DiagramExpressionModel get() {
		if(dem == null) dem = new DiagramExpressionModel();
		return dem;
	}

	public ArrayList<Class> getClasses(){
		return arrClass;
	}
	public ArrayList<UseCase> getUseCases(){
		return arrUseCases;
	}
	public ArrayList<Connection> getConnections(){
		return arrConnections;
	}
	public void createConnectionClass(String newClass){
		boolean classExists = false;
		// Check if class already exists
		for(Class tmpClass : arrClass) {
			if(tmpClass.getName().equals(newClass))	classExists = true;
		}
		
		if(classExists) {
			System.out.println("Class " + newClass + " already exists");
		} else {
			arrClass.add(new Class(newClass));
			System.out.println("Class " + newClass + " created");
		}
		notifyall();
	}
	public void createConnectionUseCase(String newUseCase){
		boolean useCaseExists = false;
		// Check if Use Case already exists
		for(UseCase tmpUseCase : arrUseCases) {
			if(tmpUseCase.getName().equals(newUseCase)) useCaseExists = true; 
		}
		
		if(useCaseExists) {
			System.out.println("UseCase " + newUseCase + " already exists");
		} else {
			arrUseCases.add(new UseCase(newUseCase));
			System.out.println("UseCase " + newUseCase + " Created");
		}
		notifyall();
	}
	
	/**
	 * createConnection creates a connection between a class and a usecase and sets the CRUD values.
	 */
	public void createConnection(Class conClass, UseCase conUseCase, boolean create, boolean read, boolean update, boolean delete){
		boolean connectionExists = false;
		// Check if connections exists, and if so, modify that connection.
		for(Connection tmpConnection : arrConnections) {
			if(tmpConnection.getConnectedClass().getName().equals(conClass.getName()) &&
					tmpConnection.getConnectedUseCase().getName().equals(conUseCase.getName())) {
				tmpConnection.setCreate(create);
				tmpConnection.setRead(read);
				tmpConnection.setUpdate(update);
				tmpConnection.setDelete(delete);
				connectionExists = true;
				System.out.println("Connection Modified");
			}
		}
		// Connection does not exist, add new connection.
		if(!connectionExists) {
			Connection newConnection = new Connection(conClass, conUseCase);
			newConnection.setCreate(create);
			newConnection.setRead(read);
			newConnection.setUpdate(update);
			newConnection.setDelete(delete);
			arrConnections.add(newConnection);
			System.out.println("Connection Created");
		}
		notifyall();
	}
	
	public boolean removeConnectionClass(Class c) {
		for(Connection con : arrConnections) {
			if(con.getConnectedClass() == c) {
				System.out.println("Connection removed (contains a deleted class)");
				arrConnections.remove(con);
			}
		}
		
		boolean removeSuccesful = arrClass.remove(c);
		if(removeSuccesful) {
			System.out.println("Class deleted");
			notifyall();
		}
		return removeSuccesful;
	}
	
	public boolean removeConnectionUseCase(UseCase u) {
		for(Connection con : arrConnections) {
			if(con.getConnectedUseCase() == u) {
				System.out.println("Connection removed (contains a deleted use case)");
				arrConnections.remove(con);
			}
		}
		
		boolean removeSuccesful = arrUseCases.remove(u);
		if(removeSuccesful) {
			System.out.println("Use Case deleted");
			notifyall();
		}
		return removeSuccesful;
	}
	
	public boolean removeConnection(Connection c){
		boolean removeSuccesful = arrConnections.remove(c);
		if(removeSuccesful) {
			System.out.println("Connection deleted");
			notifyall();
		}
		return removeSuccesful;
	}
	
	@Override
	public void notifyall() {
		System.out.println("Notification process initialised");
		System.out.println(arrObservers.size());
		for(Observer observer:arrObservers){
			observer.update(this);
		}
	}

	@Override
	public void updateModel() {
		System.out.println("update called on model");
		notifyall();
	}

	@Override
	public void addObserver(Observer o) {
		System.out.println("Observer: "+o.getClass()+" added!");
		arrObservers.add(o);
	}
}
